package com.gnerv.sylvanas.framework.core.config;

import com.gnerv.sylvanas.framework.core.autoconfigure.FrameworkCoreConfigProperties;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskDecorator;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author Gnerv LiGen
 */
@Slf4j
@EnableAsync
@Configuration
public class ThreadPoolConfig {

    @Resource
    private FrameworkCoreConfigProperties frameworkCoreConfigProperties;

    @Bean
    public Executor executor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 初始化的线程数
        executor.setCorePoolSize(frameworkCoreConfigProperties.getThreadPool().getCorePoolSize());
        // 线程池最大的线程数
        executor.setMaxPoolSize(frameworkCoreConfigProperties.getThreadPool().getMaxPoolSize());
        // 用来缓冲执行任务的队列
        executor.setQueueCapacity(frameworkCoreConfigProperties.getThreadPool().getQueueCapacity());
        // 当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
        executor.setKeepAliveSeconds(frameworkCoreConfigProperties.getThreadPool().getKeepAliveSeconds());
        // 线程池关闭的时候等待所有任务都完成再继续销毁
        executor.setWaitForTasksToCompleteOnShutdown(frameworkCoreConfigProperties.getThreadPool().isWaitForTasksToCompleteOnShutdown());
        // 超过这个时候还没有销毁就强制销毁
        executor.setAwaitTerminationSeconds(frameworkCoreConfigProperties.getThreadPool().getAwaitTerminationSeconds());
        executor.setAllowCoreThreadTimeOut(frameworkCoreConfigProperties.getThreadPool().isAllowCoreThreadTimeOut());
        // 线程池名的前缀
        executor.setThreadNamePrefix(frameworkCoreConfigProperties.getThreadPool().getThreadNamePrefix());
        // 线程池对拒绝任务的处理策略：这里采用了CallerRunsPolicy策略，
        // 当线程池没有处理能力的时候，该策略会直接在 execute 方法的调用线程中运行被拒绝的任务；
        // 如果执行程序已关闭，则会丢弃该任务
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 自定义定义装饰器 异步传递上下文信息
        executor.setTaskDecorator(new RequestContextTaskDecorator());
        return executor;
    }

    static class RequestContextTaskDecorator implements TaskDecorator {
        @Nonnull
        @Override
        public Runnable decorate(@Nonnull Runnable runnable) {
            // 异步传递上下文信息
            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
            return () -> {
                try {
                    // 设置异步线程的上下文信息
                    RequestContextHolder.setRequestAttributes(requestAttributes);
                    runnable.run();
                } finally {
                    // 结束后清除异步线程的上下文信息
                    RequestContextHolder.resetRequestAttributes();
                }
            };
        }
    }
}
